<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="Python装饰器进阶">
<meta name="twitter:description" content="<p>装饰器进阶：元信息，基于类的装饰器；用装饰器来包装argparse模块;atargparse代码和示例</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/python-decorator-2.html"/>
<meta property="og:title" content="来玩魔王的咚 | Python装饰器进阶" />
<meta property="og:description" content="<p>装饰器进阶：元信息，基于类的装饰器；用装饰器来包装argparse模块;atargparse代码和示例</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>装饰器进阶：元信息，基于类的装饰器；用装饰器来包装argparse模块;atargparse代码和示例</p>" />

    <meta name="tags" content="装饰器" />
    <meta name="tags" content="命令行参数" />
    <meta name="tags" content="python模块" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li class="active"><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-07-04 22:30:00+08:00">
                <script>document.write(moment('2020-07-04 22:30:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-07-04 22:30:00+08:00">
                <script>document.write(moment('2020-07-09 21:30:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            Python装饰器进阶
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#zhuang-shi-qi-de-yuan-xin-xi">装饰器的元信息</a></li>
<li><a href="#ji-yu-lei-de-zhuang-shi-qi">基于类的装饰器</a><ul>
<li><a href="#ke-diao-yong-de-dui-xiang">可调用的对象</a></li>
<li><a href="#yong-lei-xie-zhuang-shi-qi">用类写装饰器</a></li>
<li><a href="#zhi-chi-can-shu">支持参数</a></li>
<li><a href="#yong-lei-lai-zhuang-shi-lei-de-fang-fa">用类来装饰类的方法</a></li>
</ul>
</li>
<li><a href="#yong-zhuang-shi-qi-lai-bao-zhuang-argparse-mo-kuai">用装饰器来包装argparse模块</a><ul>
<li><a href="#jian-dan-de-argparse-shi-yong-shi-li">简单的argparse使用示例</a></li>
<li><a href="#qi-wang-de-xiao-guo">期望的效果</a></li>
<li><a href="#mo-kuai-de-shi-xian">模块的实现</a></li>
</ul>
</li>
<li><a href="#wan-zheng-de-atargparse">完整的atargparse</a><ul>
<li><a href="#he-xin-dai-ma">核心代码</a></li>
<li><a href="#dao-chu-mo-kuai-nei-de-han-shu">导出模块内的函数</a></li>
<li><a href="#shi-yong-shi-li">使用示例</a></li>
</ul>
</li>
</ul>
</div>
<p>这篇讲一些装饰器的进阶内容。  </p>
<h3 id="zhuang-shi-qi-de-yuan-xin-xi"><a class="toclink" href="#zhuang-shi-qi-de-yuan-xin-xi">装饰器的元信息</a></h3>
<p>重新给出装饰器的模板，使用这个模板可以保留被装饰函数的元信息:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">functools</span>

<span class="k">def</span> <span class="nf">func_name_2</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;二层装饰器模板&quot;&quot;&quot;</span>
    <span class="nd">@functools</span><span class="o">.</span><span class="n">wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="c1"># 添加调用函数前，要执行的代码</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="c1"># 添加调用函数后，要执行的代码</span>
        <span class="k">return</span> <span class="n">res</span>
    <span class="k">return</span> <span class="n">wrapper</span>

<span class="k">def</span> <span class="nf">func_name_3</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">):</span>  <span class="c1"># 括号内可以随意加参数</span>
    <span class="sd">&quot;&quot;&quot;三层装饰器模板&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">func</span><span class="p">):</span> 
        <span class="nd">@functools</span><span class="o">.</span><span class="n">wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
        <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
            <span class="c1"># 添加调用函数前，要执行的代码</span>
            <span class="n">res</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
            <span class="c1"># 添加调用函数后，要执行的代码</span>
            <span class="k">return</span> <span class="n">res</span>
        <span class="k">return</span> <span class="n">wrapper</span>
    <span class="k">return</span> <span class="n">decorator</span>
</code></pre></div>

<p>这次在装饰器内部的wrapper函数上，加了一个装饰器<code>@functools.wraps(func)</code>。<br>
这是python提供的装饰器。它的效果是把作为参数传递给这个装饰器的 func 函数的元信息拷贝到被它装饰的函数上。函数的元信息包括docstring、name、参数列表等等。  </p>
<p>如果不加，你会发现被装饰之后，函数的函数名<code>func_name.__name__</code>会变成wrapper。下面是示例代码:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">functools</span>
<span class="kn">import</span> <span class="nn">time</span>

<span class="k">def</span> <span class="nf">show_time</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;复制元信息&quot;&quot;&quot;</span>
    <span class="nd">@functools</span><span class="o">.</span><span class="n">wraps</span><span class="p">(</span><span class="n">func</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Now is </span><span class="si">{</span><span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">res</span>
    <span class="k">return</span> <span class="n">wrapper</span>

<span class="k">def</span> <span class="nf">show_time2</span><span class="p">(</span><span class="n">func</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;不对元信息进行操作&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Now is </span><span class="si">{</span><span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1"> %H:%M:%S&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="n">res</span> <span class="o">=</span> <span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">res</span>
    <span class="k">return</span> <span class="n">wrapper</span>

<span class="nd">@show_time</span>
<span class="k">def</span> <span class="nf">say_hello</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

<span class="nd">@show_time2</span>
<span class="k">def</span> <span class="nf">say_hi</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;say_hello is&#39;</span><span class="p">,</span> <span class="n">say_hello</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
<span class="n">say_hello</span><span class="p">(</span><span class="s2">&quot;Tom&quot;</span><span class="p">)</span>

<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;say_hi is&#39;</span><span class="p">,</span> <span class="n">say_hi</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span>
<span class="n">say_hi</span><span class="p">(</span><span class="s2">&quot;Jerry&quot;</span><span class="p">)</span>
</code></pre></div>

<p>这里给了2个函数和2个装饰器，都只有很小的差别。运行的结果如下：</p>
<div class="highlight"><pre><span></span><code>say_hello is say_hello
Now is <span class="m">2020</span>-07-03 <span class="m">15</span>:58:41
Hello Tom
say_hi is wrapper
Now is <span class="m">2020</span>-07-03 <span class="m">15</span>:58:41
Hello Jerry
</code></pre></div>

<p>这个代码不影响功能，所以写不写，功能上都是一样的。<br>
如果需要用到函数原本的元信息，就把这个装饰器用上。如果用不到的话，似乎无所谓。也可能以后或者别人会用上，加上似乎没什么问题。  </p>
<h3 id="ji-yu-lei-de-zhuang-shi-qi"><a class="toclink" href="#ji-yu-lei-de-zhuang-shi-qi">基于类的装饰器</a></h3>
<p>基本的装饰器就是用函数来装饰函数。装饰器不仅可以是函数，也可以是类。被装饰的也可以不是函数而是类。那么自然也可以用类来装饰类。<br>
这里要讲的属于用类来做装饰器，也就是用类替换装饰器内部的wrapper函数。函数被装饰后，实际就变成了装饰器内部的wrapper函数。之后执行被装饰函数，就是执行wrapper函数。如果替换成类，实际是类实例化后的对象。那么执行被装饰函数实际就是执行对象，只要这个对象也是可以被执行的，或者叫可调用（callable）。  </p>
<h4 id="ke-diao-yong-de-dui-xiang"><a class="toclink" href="#ke-diao-yong-de-dui-xiang">可调用的对象</a></h4>
<p>如果类定义了<code>__call__</code>方法，那么它的实例可以作为函数进行调用:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Student</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Hellp </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>

<span class="n">Student</span><span class="p">(</span><span class="s1">&#39;Tom&#39;</span><span class="p">)()</span>
</code></pre></div>

<p>同样是可调用，类有比函数更加多的特性，比如记录属性（当然函数通过闭包也是可以实现的），比如继承等等。  </p>
<h4 id="yong-lei-xie-zhuang-shi-qi"><a class="toclink" href="#yong-lei-xie-zhuang-shi-qi">用类写装饰器</a></h4>
<p>基于类写，就是下面这样:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Decorator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="nd">@Decorator</span>
<span class="k">def</span> <span class="nf">test</span><span class="p">():</span>
    <span class="k">pass</span>
</code></pre></div>

<p>由于@修饰符会把被装饰函数传递给装饰器，传递的参数直接就被<code>__init__</code>处理好了。所以这看起来就像一个普通的类。<br>
换个方式理解，原本二层装饰器在@的时候会传入被装饰函数执行一次，然后返回一个可调用对消。现在是一个类，传入被装饰函数@执行，就是把被装饰函数作为参数进行实例化。实例化后的结果也是一个可调用对象，逻辑通。  </p>
<p>使用了类，就可以记录下状态了:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Counter</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="nd">@Counter</span>
<span class="k">def</span> <span class="nf">foo</span><span class="p">():</span>
    <span class="k">pass</span>
<span class="c1"># 装饰器等效代码</span>
<span class="c1">#foo = Counter(foo)</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
    <span class="n">foo</span><span class="p">()</span>

<span class="nb">print</span><span class="p">(</span><span class="n">foo</span><span class="o">.</span><span class="n">count</span><span class="p">)</span> 
</code></pre></div>

<p>这里同样给出了不使用装饰器的等效代码。  </p>
<h4 id="zhi-chi-can-shu"><a class="toclink" href="#zhi-chi-can-shu">支持参数</a></h4>
<p>支持参数的情况，就和三层装饰器一样，外面再套一层函数:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">func_name_3</span><span class="p">(</span><span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">):</span>  <span class="c1"># 括号内可以随意加参数</span>
    <span class="sd">&quot;&quot;&quot;三层装饰器模板&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">func</span><span class="p">):</span> 
        <span class="c1"># 实例化之前可以做一些操作</span>
        <span class="k">return</span> <span class="n">Decorator</span><span class="p">(</span><span class="n">func</span><span class="p">,</span> <span class="n">arg1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">)</span>  <span class="c1"># 示例话的时候，可以传入更多参数</span>
    <span class="k">return</span> <span class="n">decorator</span>

<span class="k">class</span> <span class="nc">Decorator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>
        <span class="c1"># 还可以添加属性</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="c1"># 添加调用函数前，要执行的代码</span>
        <span class="n">res</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="c1"># 添加调用函数后，要执行的代码</span>
        <span class="k">return</span> <span class="n">res</span>
</code></pre></div>

<p>这里的写法，没有在类外直接套一层函数，而是把类的定义移到了全局作用域。<br>
用上了类，发现可以操作的空间更大，更灵活了，有很多地方可以添加代码。  </p>
<h4 id="yong-lei-lai-zhuang-shi-lei-de-fang-fa"><a class="toclink" href="#yong-lei-lai-zhuang-shi-lei-de-fang-fa">用类来装饰类的方法</a></h4>
<p>要装饰类的方法，只要当做是一个函数那样做就可以了。<br>
不过，当使用类来做装饰器的时候会遇到个问题，用类写的装饰器不能直接用在装饰类的方法上。这里给出解决的办法。<br>
先看下错误的想当然的写法:</p>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="nc">Decorator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="nd">@Decorator</span>
    <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>
</code></pre></div>

<p>方法被装饰后，变成了类的一个属性，而不是方法。主要是被装饰的方法执行的时候会缺少self参数。  </p>
<p>要解决这个问题，可以定义一个简单的装饰器，什么也不做，仅仅把可调用对象包装成函数:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="n">call</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">call</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">wrapper</span>

<span class="k">class</span> <span class="nc">Decorator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">func</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">func</span> <span class="o">=</span> <span class="n">func</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">func</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="nd">@method</span>
    <span class="nd">@Decorator</span>
    <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">pass</span>
</code></pre></div>

<h3 id="yong-zhuang-shi-qi-lai-bao-zhuang-argparse-mo-kuai"><a class="toclink" href="#yong-zhuang-shi-qi-lai-bao-zhuang-argparse-mo-kuai">用装饰器来包装argparse模块</a></h3>
<p>这里，假设你已经会使用argparse了。  </p>
<h4 id="jian-dan-de-argparse-shi-yong-shi-li"><a class="toclink" href="#jian-dan-de-argparse-shi-yong-shi-li">简单的argparse使用示例</a></h4>
<p>直接上代码了:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">argparse</span>

<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">()</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--count&#39;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;重复的次数&quot;</span><span class="p">)</span>
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--name&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;World&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;你的名字&quot;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">!&#39;</span><span class="p">)</span>

<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="n">hello</span><span class="p">(</span><span class="o">**</span><span class="nb">vars</span><span class="p">(</span><span class="n">args</span><span class="p">))</span>
</code></pre></div>

<p>这个例子比较简单，就2个参数，也只用了模块最基本的一些功能。<br>
执行效果:</p>
<div class="highlight"><pre><span></span><code>&gt; python study1.py -h
usage: study1.py [-h] [-c COUNT] [-n NAME]

optional arguments:
  -h, --help            show this help message and exit
  -c COUNT, --count COUNT
                        重复的次数
  -n NAME, --name NAME  你的名字

&gt; python study1.py --count=3 --name=Tom
Hello Tom!
Hello Tom!
Hello Tom!
</code></pre></div>

<h4 id="qi-wang-de-xiao-guo"><a class="toclink" href="#qi-wang-de-xiao-guo">期望的效果</a></h4>
<p>受到Click模块的启发，我也想用装饰器这样魔幻的方式来定义命令行参数。<br>
代码实现后的调用方式是这样的:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">atargparse</span>

<span class="nd">@atargparse</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--count&#39;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;重复的次数&quot;</span><span class="p">)</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--name&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;World&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;你的名字&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">!&#39;</span><span class="p">)</span>

<span class="n">hello</span><span class="p">()</span>
</code></pre></div>

<p>这样的实现方式，可以把命令行参数的定义直接和被调用的函数绑在一起。参数的定义和调整灵活。  </p>
<h4 id="mo-kuai-de-shi-xian"><a class="toclink" href="#mo-kuai-de-shi-xian">模块的实现</a></h4>
<p>文件的结构如下:</p>
<div class="highlight"><pre><span></span><code>Folder
├─ main.py
└─ atargparse
   ├─ __init__.py
   └─ cli.py
</code></pre></div>

<p>接下来要实现atargparse模块。  </p>
<h5 id="dao-chu-mo-kuai-zhong-ding-yi-de-han-shu"><a class="toclink" href="#dao-chu-mo-kuai-zhong-ding-yi-de-han-shu">导出模块中定义的函数</a></h5>
<p>这个文件保持空文件也行，不过要调用目录中其他文件里定义的函数就得带上文件名:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">atargparse</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">decorator</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">test</span><span class="p">():</span>
    <span class="k">pass</span>
</code></pre></div>

<p>要想不带文件名，直接调用函数名，也就是上一小节那样的调用方式，有以下几个办法:</p>
<ol>
<li>将atargparse目录改为atargparse.py文件，在里面写代码。</li>
<li>将代码都写在<code>__init__.py</code>文件中。</li>
<li>在<code>__init__.py</code>中，把需要给外部调用的内容导出。</li>
</ol>
<p>前两种只能单文件，适合模块代码不多的情况。这里代码也不多，但还是按第三个方法演示。<br>
在<code>__init__.py</code>中将外部需要调用的函数导出:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">command</span>
<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">option</span>
</code></pre></div>

<h5 id="zhuang-shi-qi-han-shu-de-shi-xian"><a class="toclink" href="#zhuang-shi-qi-han-shu-de-shi-xian">装饰器(函数)的实现</a></h5>
<p>模块的主函数如下:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">argparse</span>

<span class="k">def</span> <span class="nf">option</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;添加参数</span>
<span class="sd">    仅将要添加的参数存入函数的 __atargparse_params__ 属性中</span>
<span class="sd">    等到运行解析之前，才会真正添加到 ArgumentParser 对象中</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s2">&quot;__atargparse_params__&quot;</span><span class="p">):</span>
            <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">f</span>
    <span class="k">return</span> <span class="n">decorator</span>

<span class="k">def</span> <span class="nf">command</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
        <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s1">&#39;__atargparse_params__&#39;</span><span class="p">):</span>
            <span class="n">params</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span>
            <span class="n">params</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
            <span class="k">del</span> <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">params</span> <span class="o">=</span> <span class="p">[]</span>

        <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span>
            <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="o">*</span><span class="n">param</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="o">**</span><span class="n">param</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

        <span class="k">return</span> <span class="n">Command</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">parser</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">decorator</span>

<span class="k">class</span> <span class="nc">Command</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">parser</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">callback</span> <span class="o">=</span> <span class="n">callback</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">parser</span> <span class="o">=</span> <span class="n">parser</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">callback</span><span class="p">(</span><span class="o">**</span><span class="nb">vars</span><span class="p">(</span><span class="n">args</span><span class="p">))</span>
</code></pre></div>

<p>这里只简单的实现了argparse里最基本的用法。更多的功能，比如子命令，参数组、互斥参数等，则还需要更多代码。不过通过装饰器来封装的思路已经很明确了。  </p>
<h5 id="bian-yi-qi-bao-gao-han-shu-que-shao-can-shu"><a class="toclink" href="#bian-yi-qi-bao-gao-han-shu-que-shao-can-shu">编译器报告函数缺少参数</a></h5>
<p>这是一个小问题。原来函数的定义是包含参数的，经过装饰器包装后，调用的函数被替换掉了，不再需要提供参数的。<br>
运行没有问题，但是编译器的错误提示一直在那里。可以用下面的办法解决:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">atargparse</span>

<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">!&#39;</span><span class="p">)</span>

<span class="nd">@atargparse</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--count&#39;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;重复的次数&quot;</span><span class="p">)</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--name&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;World&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;你的名字&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">hello</span><span class="p">(</span><span class="o">*</span><span class="n">arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="n">run</span><span class="p">()</span>
</code></pre></div>

<h3 id="wan-zheng-de-atargparse"><a class="toclink" href="#wan-zheng-de-atargparse">完整的atargparse</a></h3>
<p>实现了argparse的主要功能，够平时用了。具体是以下这些:</p>
<ul>
<li>ArgumentParser 对象：@atargparse.command()</li>
<li>add_argument() 方法：@atargparse.option()</li>
<li>parse_args() 方法：执行前自动调用</li>
<li>子命令 add_subparsers() 方法：@atargparse.group()</li>
<li>参数组 add_argument_group() 方法：@atargparse.exclusive_option()</li>
<li>互斥 add_mutually_exclusive_group() 方法：@atargparse.group_option()</li>
</ul>
<h4 id="he-xin-dai-ma"><a class="toclink" href="#he-xin-dai-ma">核心代码</a></h4>
<div class="highlight"><pre><span></span><code><span class="c1"># atargparse/cli.py</span>

<span class="kn">import</span> <span class="nn">argparse</span>

<span class="k">def</span> <span class="nf">_add_option</span><span class="p">(</span><span class="n">group</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;添加参数</span>
<span class="sd">    仅将要添加的参数存入函数的 __atargparse_params__ 属性中</span>
<span class="sd">    等到运行解析之前，才会真正添加到 ArgumentParser 对象中</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s2">&quot;__atargparse_params__&quot;</span><span class="p">):</span>
            <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">group</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">f</span>
    <span class="k">return</span> <span class="n">decorator</span>

<span class="k">def</span> <span class="nf">option</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;add_argument() 方法</span>
<span class="sd">    name or flags - 一个命名或者一个选项字符串的列表，例如 foo 或 -f, --foo。</span>
<span class="sd">    action - 当参数在命令行中出现时使用的动作基本类型。</span>
<span class="sd">    nargs - 命令行参数应当消耗的数目。</span>
<span class="sd">    const - 被一些 action 和 nargs 选择所需求的常数。</span>
<span class="sd">    default - 当参数未在命令行中出现时使用的值。</span>
<span class="sd">    type - 命令行参数应当被转换成的类型。</span>
<span class="sd">    choices - 可用的参数的容器。</span>
<span class="sd">    required - 此命令行选项是否可省略 （仅选项可用）。</span>
<span class="sd">    help - 一个此选项作用的简单描述。</span>
<span class="sd">    metavar - 在使用方法消息中使用的参数值示例。</span>
<span class="sd">    dest - 被添加到 parse_args() 所返回对象上的属性名。</span>

<span class="sd">    对于子命令，还支持 aliases 参数</span>
<span class="sd">    aliases - 它允许多个字符串指向同一子解析器。</span>
<span class="sd">        subparsers.add_parser(&#39;checkout&#39;, aliases=[&#39;co&#39;, &#39;check_out&#39;])</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">_add_option</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">exclusive_option</span><span class="p">(</span><span class="n">group_name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;互斥组：只有一个参数在命令行中可用</span>
<span class="sd">    如果 group_name 以 _T 结尾，就是 required=True，表示至少提供一个参数</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">required</span> <span class="o">=</span> <span class="n">group_name</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;_T&#39;</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">_add_option</span><span class="p">((</span><span class="s1">&#39;exclusive&#39;</span><span class="p">,</span> <span class="n">group_name</span><span class="p">,</span> <span class="n">required</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">group_option</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">description</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;参数组：分组显示参数。默认是将命令行参数分为位置参数和可选参数两组</span>
<span class="sd">    接受 title 和 description 参数，它们可被用来定制显示内容。每一次调用，2个参数都必须写上。</span>
<span class="sd">    title同时用于区分组，严格的按照字符匹配。</span>
<span class="sd">    description仅在第一次调用的时候要用到。之后的调用参数不能省，可以传None或空字符。</span>
<span class="sd">    这里的2个参数和之后要调用的add_argument()方法的参数无冲突，见option函数的参数说明。</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">_add_option</span><span class="p">((</span><span class="s1">&#39;group&#39;</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">description</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">_parser_add_params</span><span class="p">(</span><span class="n">parser</span><span class="p">,</span> <span class="n">f</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;真正添加参数</span>
<span class="sd">    将 f 的 __atargparse_params__ 属性，取添并删除</span>
<span class="sd">    调用 ArgumentParser 的 add_argument 方法，向对象中真正添加参数</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s1">&#39;__atargparse_params__&#39;</span><span class="p">):</span>
        <span class="n">params</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span>
        <span class="n">params</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span>
        <span class="k">del</span> <span class="n">f</span><span class="o">.</span><span class="n">__atargparse_params__</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">params</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="n">group_dic</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span>
        <span class="n">group</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">param</span>
        <span class="k">if</span> <span class="n">group</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
            <span class="k">continue</span>

        <span class="n">method</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="o">*</span><span class="n">group_args</span> <span class="o">=</span> <span class="n">group</span>
        <span class="n">group_obj</span> <span class="o">=</span> <span class="n">group_dic</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">group_obj</span><span class="p">:</span>
            <span class="n">group_obj</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
            <span class="k">continue</span>
        <span class="k">if</span> <span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;exclusive&#39;</span><span class="p">:</span>
            <span class="n">required</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="o">=</span> <span class="n">group_args</span>
            <span class="n">group_obj</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_mutually_exclusive_group</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="n">required</span><span class="p">)</span>
            <span class="n">group_dic</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">group_obj</span>
            <span class="n">group_obj</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;group&#39;</span><span class="p">:</span>
            <span class="n">title</span> <span class="o">=</span> <span class="n">name</span>
            <span class="n">description</span><span class="p">,</span> <span class="o">*</span><span class="n">_</span> <span class="o">=</span> <span class="n">group_args</span>
            <span class="n">group_obj</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">add_argument_group</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="n">description</span><span class="p">)</span>
            <span class="n">group_dic</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">group_obj</span>
            <span class="n">group_obj</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">_init_parser</span><span class="p">(</span><span class="n">has_sub</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;创建 ArgumentParser 对象&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
        <span class="n">fmt_cls</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;formatter_class&#39;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">fmt_cls</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">fmt_cls</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
            <span class="n">formatter_class</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">argparse</span><span class="p">,</span> <span class="n">fmt_cls</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">formatter_class</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
                <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">&#39;formatter_class&#39;</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">kwargs</span><span class="p">[</span><span class="s1">&#39;formatter_class&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">formatter_class</span>

        <span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
        <span class="n">_parser_add_params</span><span class="p">(</span><span class="n">parser</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">has_sub</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">Group</span><span class="p">(</span><span class="n">parser</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">Command</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">parser</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">decorator</span>

<span class="k">def</span> <span class="nf">command</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;创建 ArgumentParser 对象，所有的参数都应当作为关键字参数传入</span>
<span class="sd">    prog - 程序的名称（默认值：sys.argv[0]）</span>
<span class="sd">    usage - 描述程序用途的字符串（默认值：从添加到解析器的参数生成）</span>
<span class="sd">    description - 在参数帮助文档之前显示的文本（默认值：无）</span>
<span class="sd">    epilog - 在参数帮助文档之后显示的文本（默认值：无）</span>
<span class="sd">    parents - 一个 ArgumentParser 对象的列表，它们的参数也应包含在内</span>
<span class="sd">    formatter_class - 用于自定义帮助文档输出格式的类。多行帮助用 RawDescriptionHelpFormatter</span>
<span class="sd">    prefix_chars - 可选参数的前缀字符集合（默认值： &#39;-&#39;）</span>
<span class="sd">    fromfile_prefix_chars - 当需要从文件中读取其他参数时，用于标识文件名的前缀字符集合（默认值： None）</span>
<span class="sd">    argument_default - 参数的全局默认值（默认值： None）</span>
<span class="sd">    conflict_handler - 解决冲突选项的策略（通常是不必要的）</span>
<span class="sd">    add_help - 为解析器添加一个 -h/--help 选项（默认值： True）</span>
<span class="sd">    allow_abbrev - 如果缩写是无歧义的，则允许缩写长选项 （默认值：True）    </span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">_init_parser</span><span class="p">(</span><span class="n">has_sub</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">group</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;创建可以添加子命令的 ArgumentParser 对象&quot;&quot;&quot;</span>
    <span class="k">return</span> <span class="n">_init_parser</span><span class="p">(</span><span class="n">has_sub</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Command</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="n">parser</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">callback</span> <span class="o">=</span> <span class="n">callback</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">parser</span> <span class="o">=</span> <span class="n">parser</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">callback</span><span class="p">(</span><span class="o">**</span><span class="nb">vars</span><span class="p">(</span><span class="n">args</span><span class="p">))</span>


<span class="k">class</span> <span class="nc">Group</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>

    <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">parser</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">parser</span> <span class="o">=</span> <span class="n">parser</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">subparsers</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">init_subparsers</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">init_subparsers</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">subparsers</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">add_subparsers</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s1">&#39;支持的子命令&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">&#39;子命令列表&#39;</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">subparsers</span>

    <span class="k">def</span> <span class="nf">command</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
        <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
            <span class="n">f_name</span> <span class="o">=</span> <span class="n">name</span> <span class="ow">or</span> <span class="n">f</span><span class="o">.</span><span class="vm">__name__</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;_&quot;</span><span class="p">,</span> <span class="s2">&quot;-&quot;</span><span class="p">)</span>
            <span class="n">parser_sub</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">subparsers</span><span class="o">.</span><span class="n">add_parser</span><span class="p">(</span><span class="n">f_name</span><span class="p">)</span>
            <span class="n">_parser_add_params</span><span class="p">(</span><span class="n">parser_sub</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span>
            <span class="n">parser_sub</span><span class="o">.</span><span class="n">set_defaults</span><span class="p">(</span><span class="n">func</span><span class="o">=</span><span class="n">f</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">f</span>
        <span class="k">return</span> <span class="n">decorator</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">option</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;调用模块中的option函数</span>
<span class="sd">        无论是调用模块的option函数，还是调用对象的option方法，都是一样的</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">option</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="nd">@staticmethod</span>
    <span class="k">def</span> <span class="nf">exclusive_option</span><span class="p">(</span><span class="n">group_name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">exclusive_option</span><span class="p">(</span><span class="n">group_name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>

    <span class="k">def</span> <span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
        <span class="n">args</span> <span class="o">=</span> <span class="nb">vars</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
        <span class="n">func</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s1">&#39;func&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">func</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">func</span><span class="p">(</span><span class="o">**</span><span class="n">args</span><span class="p">)</span>
</code></pre></div>

<h4 id="dao-chu-mo-kuai-nei-de-han-shu"><a class="toclink" href="#dao-chu-mo-kuai-nei-de-han-shu">导出模块内的函数</a></h4>
<div class="highlight"><pre><span></span><code><span class="c1"># argparse/__init__.py</span>

<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">command</span>
<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">group</span>
<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">option</span>
<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">exclusive_option</span>
<span class="kn">from</span> <span class="nn">.cli</span> <span class="kn">import</span> <span class="n">group_option</span>
</code></pre></div>

<h4 id="shi-yong-shi-li"><a class="toclink" href="#shi-yong-shi-li">使用示例</a></h4>
<p>这里的示例用了子命令，以及互斥参数:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">atargparse</span>
<span class="kn">import</span> <span class="nn">textwrap</span>

<span class="n">EPILOG</span><span class="o">=</span><span class="n">textwrap</span><span class="o">.</span><span class="n">dedent</span><span class="p">(</span><span class="s2">&quot;&quot;&quot;</span><span class="se">\</span>
<span class="s2">        hello:       say Hello</span>
<span class="s2">        echo:        回显消息</span>

<span class="s2">    用法示例：</span>
<span class="s2">        python </span><span class="si">%(prog)s</span><span class="s2"> hello --count=3 --name=Tom</span>
<span class="s2">        python </span><span class="si">%(prog)s</span><span class="s2"> echo &#39;Your Message&#39;</span>
<span class="s2">        python </span><span class="si">%(prog)s</span><span class="s2"> echo &#39;Your Message&#39; -u</span>

<span class="s2">    @749B</span>
<span class="s2">    &quot;&quot;&quot;</span><span class="p">)</span>

<span class="nd">@atargparse</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">&quot;打印内容&quot;</span><span class="p">,</span> <span class="n">formatter_class</span><span class="o">=</span><span class="s1">&#39;RawDescriptionHelpFormatter&#39;</span><span class="p">,</span> <span class="n">epilog</span><span class="o">=</span><span class="n">EPILOG</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="k">pass</span>

<span class="nd">@main</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-c&#39;</span><span class="p">,</span> <span class="s1">&#39;--count&#39;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;重复的次数&quot;</span><span class="p">)</span>
<span class="nd">@atargparse</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;-n&#39;</span><span class="p">,</span> <span class="s1">&#39;--name&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;World&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s2">&quot;你的名字&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">count</span><span class="p">):</span>
        <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Hello </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s1">!&#39;</span><span class="p">)</span>

<span class="nd">@main</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="nd">@main</span><span class="o">.</span><span class="n">option</span><span class="p">(</span><span class="s1">&#39;msg&#39;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;Hello World!&#39;</span><span class="p">,</span> <span class="n">metavar</span><span class="o">=</span><span class="s1">&#39;string&#39;</span><span class="p">,</span> <span class="n">nargs</span><span class="o">=</span><span class="s1">&#39;?&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">&#39;要打印的字符&#39;</span><span class="p">)</span>
<span class="nd">@main</span><span class="o">.</span><span class="n">exclusive_option</span><span class="p">(</span><span class="s1">&#39;mode&#39;</span><span class="p">,</span> <span class="s1">&#39;-u&#39;</span><span class="p">,</span> <span class="s1">&#39;--upper&#39;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">&#39;store_true&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">&#39;全大写输出&#39;</span><span class="p">)</span>
<span class="nd">@main</span><span class="o">.</span><span class="n">exclusive_option</span><span class="p">(</span><span class="s1">&#39;mode&#39;</span><span class="p">,</span> <span class="s1">&#39;-l&#39;</span><span class="p">,</span> <span class="s1">&#39;--lower&#39;</span><span class="p">,</span> <span class="n">action</span><span class="o">=</span><span class="s1">&#39;store_true&#39;</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s1">&#39;全小写输出&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">echo</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="s1">&#39;Hello World!&#39;</span><span class="p">,</span> <span class="n">upper</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">lower</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">upper</span><span class="p">:</span>
        <span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">lower</span><span class="p">:</span>
        <span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
    <span class="nb">print</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>

<span class="n">main</span><span class="p">()</span>
</code></pre></div>

<p>注意事项:</p>
<ul>
<li>使用子命令，首先需要创建一个空函数，这里是main</li>
<li>创建的main函数必须在最上面</li>
<li>每个子命令，需要先调用<code>@main.command()</code>。这里是main函数的函数名</li>
<li>添加参数仍然是<code>@atargparse.option</code>。不过使用<code>@main.option</code>也是一样的</li>
<li>互斥组调用的第一个参数随意定一个字符串用于区分分组，如果字符串以<code>_T</code>结尾，就是<code>required=True</code>，表示至少提供一个参数</li>
</ul>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>